/***************************************************************************
 创建者: hualei
 开始时间: 2018.9.10
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2018.5.8 类的具体实现代码编写

 ***************************************************************************/
#include "maganeticsensor.h"
#include "qdom.h"
#include "domparser.h"
#include <qdebug.h>
#include <stdio.h>
#include "ethercatVendorId.h"

MaganeticSensor::MaganeticSensor(QString configFilePath)
{
    isInitialConfigOk = false;
    maganeticDevice = new MaganeticDevice;
    modbusMaster = NULL;
    isMaganeticOutOfRange = false;
    debugFlag=0;

    initialSensorByConfigFile(configFilePath);
    itDeviceName = deviceNameMap.begin();
    if( connectPort() != 1)
    {
        qDebug() << "The modbus connect failed!";
    }
    else
    {
        for(int i = 0; i < deviceNameMap.size(); i++)
        {
            positionDataMap.insert(deviceNameMap.keys().at(i), 0);
        }
        maganeticCurrentSlaveId = itDeviceName.key();
        timer.start(maganeticDevice->updatePeriod);
        QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(getPositionData()));
    }
}

int MaganeticSensor::setDebugFlag(int debugFlagIn)
{
    debugFlag=debugFlagIn;
    return 1;
}

bool MaganeticSensor::isInitialStatus()
{
    return isInitialConfigOk;
}

int MaganeticSensor::initialSensorByConfigFile(QString configFilePath)
{
    qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 初配置文件:" \
             << configFilePath;
    DomParser domparser;
    bool ok = domparser.openXml(configFilePath,QIODevice::ReadOnly);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 配置文件打开失败:"\
                 << configFilePath;
        return -1;
    }
    QDomNode deviceVendorNode = domparser.findSubNode(domparser.getRootDomElement(),"MaganeticSensor", ok);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取DeviceNumber失败:" \
                 << configFilePath;
        return -1;
    }

    // 读取设备厂商ID
    DeviceName deviceName;
    QDomNodeList deviceVendorNodeList = deviceVendorNode.childNodes();
    for(int i = 0; i < deviceVendorNodeList.count(); ++i)
    {
        // Read The "deviceVendorId" for The configFile;
        domparser.readXml(domparser.findSubNode(deviceVendorNodeList.at(i), "deviceVendorId", ok),
                          deviceName.deviceVendorId);
        if( !ok )
        {
            qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取deviceVendorId失败:" \
                     << configFilePath;
            return -2;
        }

         // Read The "deviceId" for The configFile;
        domparser.readXml(domparser.findSubNode(deviceVendorNodeList.at(i), "deviceId", ok),
                          deviceName.deviceId);
        if( !ok )
        {
            qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取deviceId失败:" \
                     << configFilePath;
            return -2;
        }

        mutex.lock();
        deviceNameMap.insert(deviceName.deviceId, deviceName);
        mutex.unlock();
    }

    // 读取串口配置信息
    QDomNode domNode = domparser.findSubNode(domparser.getRootDomElement(), "SerialSetting", ok);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取SerialSetting失败:" \
                 << configFilePath;
        return -3;
    }

    // 读取串口总线类型
    domparser.readXml(domparser.findSubNode(domNode, "ModbusType", ok),maganeticDevice->ModbusType);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取busType失败:" \
                 << configFilePath;
        return -4;
    }

    //读取串口设备名
    domparser.readXml(domparser.findSubNode(domNode, "serialDeviceName", ok),\
                      maganeticDevice->serialDeviceName);

    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取serialDeviceName失败:"\
                 << configFilePath;
        return -5;
    }

    // 读取串口波特率
    domparser.readXml(domparser.findSubNode(domNode, "baud", ok), maganeticDevice->baud);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取baud失败："\
                 << configFilePath;
        return -6;
    }

    // 读取串口校验位
    domparser.readXml(domparser.findSubNode(domNode, "parity", ok), maganeticDevice->parity);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取parity失败："\
                 << configFilePath;
        return -7;
    }

    // 读取数据位
    domparser.readXml(domparser.findSubNode(domNode, "data_bit", ok), maganeticDevice->data_bits);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取data_bit失败："\
                 << configFilePath;
        return -8;
    }

    // 读取停止位
    domparser.readXml(domparser.findSubNode(domNode, "stop_bit", ok), maganeticDevice->stop_bits);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取stop_bit失败："\
                 << configFilePath;
        return -9;
    }

    // 读取更新频率
    domparser.readXml(domparser.findSubNode(domNode, "updatePeriod", ok), maganeticDevice->updatePeriod);
    if( !ok )
    {
        qDebug() << "MaganeticSensor::initialSensorByConfigFile ==== 读取updatePeriod失败："\
                 << configFilePath;
        return -10;
    }

    domparser.closeXml(true);
    isInitialConfigOk = true;
    qDebug() << "intialConfigFile success!";

    return 1;
}


int MaganeticSensor::connectPort()
{
    if(E_MODBUS_TYPE_TCP == maganeticDevice->ModbusType)
    {
        return -1;
    }
    else if(E_MODBUS_TYPE_RTU == maganeticDevice->ModbusType)
    {
        modbusMaster =modbus_new_rtu(maganeticDevice->serialDeviceName.toStdString().data(),
                                     maganeticDevice->baud,
                                     (*maganeticDevice->parity.toStdString().data()),
                                     maganeticDevice->data_bits,
                                     maganeticDevice->stop_bits);

         modbus_set_slave(modbusMaster,itDeviceName.key());
         if (modbus_connect(modbusMaster) == -1)
         {
              qDebug()<<"Modbus485Driver::connectPort connect failed";
              modbus_free(modbusMaster);
              modbusMaster=NULL;
              return -2;
         }
         else
         {
              qDebug()<<"connect success";
              modbus_set_response_timeout(modbusMaster, 0, 500000);
              triggerParameter = getTriggerFactorValue();
              return 1;
         }
    }
    return -1;
}


void MaganeticSensor::getPositionData()
{
    if(1==debugFlag)
    {
        qDebug()<<"timeout()---MaganeticSensor::getPositionData()";
    }
    if( isInitialConfigOk == false)
    {
        return;
    }
    if(1!=checkModbusMaster())
    {
        return;
    }
    switch(itDeviceName.value().deviceVendorId)
    {
        case E_VENDOR_ID_DE_MO_TE:
        {
            int resultKey = getDeviceVendorId_1_DetectValue();
            if(resultKey != -1 )
            {
                mutex.lock();
                if( itDeviceName.key() == deviceNameMap.keys().last())
                {
                    itDeviceName = deviceNameMap.begin();
                }
                else
                {
                    itDeviceName++;
                }
                mutex.unlock();
            }
        }
        break;
    default:
        break;
    }

}

int MaganeticSensor::getDeviceVendorId_1_DetectValue()
{
    QList<int>maganeticDataList;

    unsigned char deviceId = (char)itDeviceName.key();
    uint8_t receiveData[MODBUS_RTU_MAX_ADU_LENGTH] = {0};
    uint8_t registerAddress = D_POSITION_REGISTER_FIRST_ADDRESS;

    for(int i = 0; i < D_REGISTER_NUMBER; i++)
    {
        uint8_t positionCommand[] = {deviceId, MODBUS_FC_READ_HOLDING_REGISTERS, 0x00,registerAddress++, 0x00, 0x01};

        int sendKey = modbus_send_raw_request(modbusMaster, positionCommand, 6*sizeof(uint8_t));
        modbus_receive_confirmation(modbusMaster, receiveData);

        if(sendKey == -1)
        {
            isConnectPortOk = false;
            return -1;
        }
        else
        {
            isConnectPortOk = true;
        }

        if(receiveData[0] == deviceId)
        {
            if(receiveData[1] == MODBUS_FC_READ_HOLDING_REGISTERS)
            {
                maganeticDataList << receiveData[4];
                maganeticDataList << receiveData[3];
            }
            else
            {
                return -1;
            }
        }
        else
        {
            return -1;
        }
    }
    double positionData = positionDataProcess(maganeticDataList);
    if( positionData != -1)
    {
        mutex.lock();
        positionDataMap[itDeviceName.key()] = positionData;
        mutex.unlock();
    }

    return 1;
}

double MaganeticSensor::positionDataProcess(QList<int> positionDataList)
{
    if(positionDataList.isEmpty())
    {
        return -1;
    }
    QList<int>processList = positionDataList;
    qSort(processList.begin(), processList.end());

    double positionDataMax = processList.last();
    double positionSecond = processList.at(positionDataList.size() - 2);
    double maxIndex = positionDataList.indexOf(positionDataMax);
    double secondIndex = positionDataList.indexOf(positionSecond); 
    double position = 0.0;
//    double intPosition=0.0;
//    double deviPosition=0.0;

    // 探测最大值和第二大都大于触发系数
    if( ( positionDataMax > triggerParameter) && (positionSecond > triggerParameter))
    {
//        intPosition = (maxIndex+secondIndex)/2;
//        deviPosition=1*(positionDataMax-positionSecond)/bijiaojizun;
        double maxValue = ((maxIndex*positionDataMax)/(positionDataMax+positionSecond));
        double secondValue = ((secondIndex*positionSecond)/(positionDataMax+positionSecond));
//        position = (maxIndex+secondIndex)/2;
        position = (maxValue+secondValue);
        isMaganeticOutOfRange = false;
    }
    // 最大值大于触发系数，第二大小于触发系数
    else if((positionDataMax >= triggerParameter) && (positionSecond <= triggerParameter))
    {
        if(maxIndex != -1)
        {
            position = maxIndex;
            isMaganeticOutOfRange = false;
        }
    }
    // 最大磁场强度小于触发系数
    else if( positionDataMax < triggerParameter)
    {
        isMaganeticOutOfRange = true;
        position = -100.0;
    }
    return position;
}

int MaganeticSensor::getSensorPositionValue(int deviceIdIn,double &valueOut)
{
    mutex.lock();
    if( -1 == positionDataMap.keys().indexOf(deviceIdIn))
    {
        qDebug() << "MaganeticSensor::getSensorPositionValue ==== deviceIdIn is Invalid!";
        mutex.unlock();
        return -1;
    }
    mutex.unlock();
    if(isConnectPortOk == false)
    {
        isCommunicateOk = false;
        qDebug() << "MaganeticSensor::getSensorPositionValue ==== connectPort failed!";
        return -1;
    }
    if(isMaganeticOutOfRange == true)
    {
        qDebug() << "MaganeticSensor::getSensorPositionValue ==== Maganetic Position Value Out of Range!";
        valueOut = -100;
        return 0;
    }

    mutex.lock();
    valueOut = positionDataMap.value(deviceIdIn);
    mutex.unlock();

    return 1;
}

int MaganeticSensor::setSensorDeviceId(int primaryIdIn, int targetIdIn)
{
    if(positionDataMap.keys().indexOf(primaryIdIn) == -1)
    {
        qDebug() << "MaganeticSensor::setSensorDeviceId ==== The PrimaryId Error:" << primaryIdIn;
        return 0;
    }
    if( isInitialConfigOk == false)
    {
        return -1;
    }
    if(1!=checkModbusMaster())
    {
        return -1;
    }
    if(isConnectPortOk == false)
    {
        qDebug() << "MaganeticSensor::setSensorDeviceId ==== connectPort failed!";
        return -1;
    }
    switch(itDeviceName.value().deviceVendorId)
    {
        case E_VENDOR_ID_DE_MO_TE:
        {
            DeviceName deviceName;
            int resultKey = modbus_write_register(modbusMaster, D_MODBUS_ID_ADDRESSS, targetIdIn);
            if( resultKey == 1)
            {
                mutex.lock();
                deviceName = deviceNameMap.value(primaryIdIn);
                deviceNameMap.remove(primaryIdIn);
                deviceNameMap.insert(targetIdIn,deviceName);
                mutex.unlock();
            }
            else
            {
                return -1;
            }
        }
        break;
    }
    return 1;
}

int MaganeticSensor::getTriggerFactorValue()
{
    unsigned char deviceId = itDeviceName.key();
    uint8_t triggerpCommad[] = {deviceId, MODBUS_FC_READ_HOLDING_REGISTERS,
                                0x00, D_TRIGGER_PARAMETER_REGISTER,
                                0x00, 0x01};
    uint8_t triggerpReceive[10];
    unsigned char lowByte;
    unsigned short triggerFactorData;

    modbus_send_raw_request(modbusMaster, triggerpCommad, 6*sizeof(uint8_t));
    modbus_receive_confirmation(modbusMaster, triggerpReceive);
    if(triggerpReceive[0] == itDeviceName.key() )
    {
        if(triggerpReceive[1] == MODBUS_FC_READ_HOLDING_REGISTERS)
        {
                triggerFactorData = triggerpReceive[3];
                lowByte = triggerpReceive[4];
                triggerFactorData = (triggerFactorData << 8) | lowByte;
                return triggerFactorData;
        }
        else
        {
            return -1;
        }
    }
    else
    {
        return -1;
    }
    return triggerFactorData;
}


int MaganeticSensor::checkModbusMaster()
{
    if(E_MODBUS_TYPE_TCP==maganeticDevice->ModbusType)
    {
        return -1;
    }

    if(NULL==modbusMaster && -1==itDeviceName.key())
    {
            int returnKey;
            returnKey=connectPort();
            if(1==returnKey)
            {
                maganeticCurrentSlaveId=itDeviceName.key();
                return 1;
            }
            else
            {
                return -1;
            }
    }
    else if(itDeviceName.key() !=maganeticCurrentSlaveId)
    {
        int returnKey;
        modbus_close(modbusMaster);
        modbus_free(modbusMaster);
        returnKey=connectPort();
        if(1==returnKey)
        {
            maganeticCurrentSlaveId=itDeviceName.key();
            return 1;
        }
        else
        {
            return -2;
        }
    }
    return 1;
}
